/*
 * @Author: hongbin
 * @Date: 2022-12-10 11:12:36
 * @LastEditors: hongbin
 * @LastEditTime: 2023-01-07 11:11:24
 * @Description:初始化环境
 */

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { ModelsLoad } from "./ModelLoad";

interface ICanvasLayout {
    width: number;
    height: number;
    /**
     * 像素比 越高越清晰 开销越大
     */
    pixelRatio: number;
}

interface ISetCamera {
    fov?: number;
    aspect?: number;
    near?: number;
    far?: number;
}
/**
 * 初始化 scene camera renderer lights
 */
export class BaseEnvironment extends ModelsLoad {
    renderer!: THREE.WebGLRenderer;
    camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
    lights: (THREE.HemisphereLight | THREE.DirectionalLight)[] = [];
    scene = new THREE.Scene();
    controls!: OrbitControls;

    constructor(params: THREE.WebGLRendererParameters) {
        super();
        this.initRenderer(params);
        this.initScene();
    }

    /**
     * 初始化环境
     */
    // initEnv(
    //     parameters?: THREE.WebGLRendererParameters,
    //     canvasLayout?: ICanvasLayout
    // ) {
    // this.initRenderer(parameters, canvasLayout);
    // this.initScene();
    // }

    setCamera = (params: Partial<ISetCamera>) => {
        Object.assign(this.camera, params);
    };

    /**
     * 添加灯光
     */
    protected initLights() {
        const hemisphereLight = new THREE.HemisphereLight(0xdddddd, 0xffffff, 0.8);
        hemisphereLight.position.set(0, -2, 110);
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.45);
        this.lights = [hemisphereLight, directionalLight];
        this.scene.add(...this.lights);
    }

    protected initScene() {
        this.initLights();
        this.orbitControls();
    }

    /**
     * 设置背景 十六进制颜色
     */
    setBackground(color: string) {
        this.scene.background = new THREE.Color(color);
    }

    /**
     * 添加辅助坐标
     */
    addAxis(length?: number) {
        const axes = new THREE.AxesHelper(length || 1000);
        this.scene.add(axes);
    }

    /**
     * 添加控制器
     */
    orbitControls() {
        const controls = new OrbitControls(this.camera, this.renderer.domElement);
        // controls.minDistance = -100;
        this.controls = controls;
        controls.addEventListener("change", () => {
            this.render();
        });
    }

    /**
     * 控制镜头缩放等级
     */
    zoom(min: number, max: number) {
        this.controls.minZoom = min;
        this.controls.maxZoom = max;
    }

    /**
     * 镜头移动距离限制
     */
    distance(min: number, max: number) {
        this.controls.minDistance = min;
        this.controls.maxDistance = max;
    }

    /**
     * 镜头垂直方向旋转角度 默认 0-180 即 angle(0,Math.PI)
     */
    angle(min: number, max: number) {
        this.controls.minPolarAngle = min;
        this.controls.maxPolarAngle = max;
    }

    /**
     * 手动指定尺寸
     */
    appointSize(width: number, height: number) {
        this.camera.aspect = width / height;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(width, height);
        this.render();
    }

    /**
     * 根据新尺寸 重置相关参数
     */
    protected resetLayout() {
        // const w = this.renderer.domElement.offsetWidth;
        // const h = this.renderer.domElement.offsetHeight;
        const w = window.innerWidth;
        const h = window.innerHeight;

        this.camera.aspect = w / h;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(w, h);
        this.render();
    }

    /**
     * 保证this指向
     */
    protected selfResetLayout = () => this.resetLayout.call(this);

    /**
     * 添加resize监听
     */
    listenResize() {
        window.addEventListener("resize", this.selfResetLayout);
    }

    removeResizeListen() {
        window.removeEventListener("resize", this.selfResetLayout);
    }

    /**
     * 清除scene中的物体
     */
    protected clearChildren(obj: THREE.Scene | any) {
        while (obj.children.length > 0) {
            this.clearChildren(obj.children[0]);
            obj.remove(obj.children[0]);
        }
        if (obj.geometry) obj.geometry.dispose();

        if (obj.material) {
            if (Array.isArray(obj.material)) {
                obj.material.forEach((m: THREE.Material) => m.dispose());
            } else obj.material.dispose();
        }
    }

    clearScene() {
        this.clearChildren(this.scene);
    }

    render() {
        this.renderer.render(this.scene, this.camera);
    }

    protected initRenderer(
        parameters?: THREE.WebGLRendererParameters,
        canvasLayout?: ICanvasLayout
    ) {
        this.renderer = new THREE.WebGLRenderer(parameters);
        this.renderer.outputEncoding = THREE.sRGBEncoding;
        const defLay = {
            width: window.innerWidth,
            height: window.innerHeight,
            pixelRatio: window.devicePixelRatio,
        };
        const layout = { ...defLay, ...canvasLayout };
        // 像素比 分辨率
        // this.renderer.setPixelRatio(layout.pixelRatio);
        this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        // this.renderer.setPixelRatio(1.5);
        // 设置画布大小
        this.renderer.setSize(layout.width, layout.height);
        this.resetLayout();
        return this.renderer;
    }

    /**
     * 将背景设置成透明
     */
    transparentBackGround() {
        //背景透明 主要是第二个参数 alpha
        this.renderer.setClearColor(0x000000, 0);
    }

    /**
     * @description: 设置背景颜色透明度
     * @param {number} alpha 0-透明 1-不透明
     */
    setBackGroundAlpha(alpha: number) {
        this.renderer.setClearColor(0x000000, alpha);
    }
}
